﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks;
using DGM.Objects.General;
using DGM.Objects.Msmq;
using DGM.Util.Helpers.Enums;


namespace DGM.Util.Helpers.Msmq
{
    public static class MsmqManager
    {
        private static Dictionary<string, MessageQueue> _queuesHolder;
        private static Dictionary<string, MessageQueue> QueuesHolder
        {
            get
            {
                if(_queuesHolder == null)
                {
                    _queuesHolder = new Dictionary<string, MessageQueue>();
                }
                return _queuesHolder;
            }
        }

        public static void SendToQueue(QueueType type, string queueName, object message, string messageLabel, string host=".")
        {
            var fullQueueName = GetFullQueueName(type, queueName, host);

            MessageQueue messageQueue = GetOrCreateQueue(fullQueueName, host);

            Message mm = new Message();
            mm.Body = message;
            mm.Label = messageLabel;

            messageQueue.Send(mm);
        }

        public static void ListenToQueueAsync<T>(QueueType type, string queueName, Action<ResultObject<T>> callback, string host = ".")
        {
            var fullQueueName = GetFullQueueName(type, queueName, host);

            MessageQueue messageQueue = GetOrCreateQueue(fullQueueName, host);

            messageQueue.ReceiveCompleted += delegate(object sender, ReceiveCompletedEventArgs args)
                                                 {
                                                     MessageQueue queue = sender as MessageQueue;
                                                     if(queue != null)
                                                     {
                                                         var msg = queue.EndReceive(args.AsyncResult);

                                                         if(callback != null)
                                                         {
                                                             var result = new ResultObject<T>();
                                                             msg.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
                                                             result.Data = (T)msg.Body;
                                                             callback.Invoke(result);
                                                         }
                                                         queue.BeginReceive();
                                                     }
                                                 };

            messageQueue.BeginReceive();

        }

				private static MessageQueue GetOrCreateQueue(string queueName, string host)
				{
					lock (typeof (MessageQueue))
					{
						MessageQueue result;
						if (TryGetMessageQueue(queueName, out result) == false)
						{
							if (host == "." && MessageQueue.Exists(queueName) == false)
							{
								MessageQueue.Create(queueName);
							}

							result = new MessageQueue(queueName);
							QueuesHolder.Add(queueName, result);
						}

						return result;
					}
				}

	    private static bool TryGetMessageQueue(string queueName, out MessageQueue messageQueue)
        {
            return QueuesHolder.TryGetValue(queueName, out messageQueue);
        }

        private static string GetFullQueueName(QueueType type, string name, string host)
        {
            var queueClass = EnumHelper.GetQueueClass(type);

            var result = host + queueClass + name;

            return result;
        }
    }
}
